package wiki.xsx.core.handler;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 字符串类型助手
 * @author xsx
 * @date 2019/4/8
 * @since 1.8
 */
public class StringTypeHandler {
    /**
     * 对象模板
     */
    private ValueOperations<String, Object> operations;
    /**
     * 字符串模板
     */
    private ValueOperations<String, String> stringOperations;
    /**
     * 单例对象
     */
    private static final StringTypeHandler HANDLER = new StringTypeHandler();

    private StringTypeHandler(){}

    public static StringTypeHandler getInstance(RedisTemplate redisTemplate, StringRedisTemplate stringRedisTemplate){
        HANDLER.operations = redisTemplate.opsForValue();
        HANDLER.stringOperations = stringRedisTemplate.opsForValue();
        return HANDLER;
    }

    /**
     * 设置对象(若存在则更新过期时间)
     * @since redis 2.0.0
     * @param key 键
     * @param value 对象
     * @param timeout 过期时间
     * @param unit 时间单位
     */
    public void setAsObj(String key, Object value, long timeout, TimeUnit unit){
        this.operations.set(key, value, timeout, unit);
    }

    /**
     * 设置对象
     * @since redis 2.0.0
     * @param key 键
     * @param value 对象
     */
    public void setAsObj(String key, Object value){
        this.operations.set(key, value);
    }

    /**
     * 设置字符串(若存在则更新过期时间)
     * @since redis 2.0.0
     * @param key 键
     * @param value 字符串
     * @param timeout 过期时间
     * @param unit 时间单位
     */
    public void set(String key, String value, long timeout, TimeUnit unit){
        this.stringOperations.set(key, value, timeout, unit);
    }

    /**
     * 设置字符串
     * @since redis 2.0.0
     * @param key 键
     * @param value 字符串
     */
    public void set(String key, String value){
        this.stringOperations.set(key, value);
    }

    /**
     * 批量设置对象
     * @since redis 1.0.1
     * @param map 对象集合
     */
    public void msetAsObj(Map<String, Object> map){
        this.operations.multiSet(map);
    }

    /**
     * 批量设置字符串
     * @since redis 1.0.1
     * @param map 字符串集合
     */
    public void mset(Map<String, String> map){
        this.stringOperations.multiSet(map);
    }

    /**
     * 追加新字符串
     * @since redis 2.0.0
     * @param key 键
     * @param value 字符串
     */
    public void append(String key, String value){
        this.stringOperations.append(key, value);
    }

    /**
     * 设置对象如果不存在
     * @since redis 1.0.0
     * @param key 键
     * @param value 对象
     * @param timeout 过期时间
     * @param unit 时间单位
     * @return 返回布尔值,成功true,失败false
     */
    public boolean setIfAbsentAsObj(String key, Object value, long timeout, TimeUnit unit){
        return this.operations.setIfAbsent(key, value, timeout, unit);
    }

    /**
     * 设置字符串如果不存在
     * @since redis 1.0.0
     * @param key 键
     * @param value 字符串
     * @param timeout 过期时间
     * @param unit 时间单位
     * @return 返回布尔值,成功true,失败false
     */
    public boolean setIfAbsent(String key, String value, long timeout, TimeUnit unit){
        return this.stringOperations.setIfAbsent(key, value, timeout, unit);
    }

    /**
     * 设置对象如果不存在
     * @since redis 1.0.0
     * @param key 键
     * @param value 对象
     * @return 返回布尔值,成功true,失败false
     */
    public boolean setIfAbsentAsObj(String key, Object value){
        return this.operations.setIfAbsent(key, value);
    }

    /**
     * 设置字符串如果不存在
     * @since redis 1.0.0
     * @param key 键
     * @param value 字符串
     * @return 返回布尔值,成功true,失败false
     */
    public boolean setIfAbsent(String key, String value){
        return this.stringOperations.setIfAbsent(key, value);
    }

    /**
     * 批量设置对象如果不存在
     * @since redis 1.0.1
     * @param map 对象集合
     * @return 返回布尔值,成功true,失败false
     */
    public boolean msetIfAbsentAsObj(Map<String, Object> map){
        return this.operations.multiSetIfAbsent(map);
    }

    /**
     * 批量设置字符串如果不存在
     * @since redis 1.0.1
     * @param map 字符串集合
     * @return 返回布尔值,成功true,失败false
     */
    public boolean msetIfAbsent(Map<String, String> map){
        return this.stringOperations.multiSetIfAbsent(map);
    }

    /**
     * 获取对象
     * @since redis 1.0.0
     * @param key 键
     * @param <T> 返回类型
     * @return 返回对象
     */
    public <T> T getAsObj(String key){
        return (T) this.operations.get(key);
    }

    /**
     * 获取字符串
     * @since redis 1.0.0
     * @param key 键
     * @return 返回字符串
     */
    public String get(String key){
        return this.stringOperations.get(key);
    }

    /**
     * 获取并设置新对象
     * @since redis 1.0.0
     * @param key 键
     * @param value 对象
     * @param <T> 返回类型
     * @return 返回对象
     */
    public <T> T getAndSetAsObj(String key, Object value){
        return (T) this.operations.getAndSet(key, value);
    }

    /**
     * 获取并设置新字符串
     * @since redis 1.0.0
     * @param key 键
     * @param value 字符串
     * @return 返回字符串
     */
    public String getAndSet(String key, String value){
        return this.stringOperations.getAndSet(key, value);
    }

    /**
     * 批量获取对象
     * @since redis 1.0.0
     * @param keys 键
     * @return 返回对象列表
     */
    public List mgetAsObj(String ...keys){
        return this.operations.multiGet(Arrays.asList(keys));
    }

    /**
     * 批量获取字符串
     * @since redis 1.0.0
     * @param keys 键
     * @return 返回字符串列表
     */
    public List<String> mget(String ...keys){
        return this.stringOperations.multiGet(Arrays.asList(keys));
    }

    /**
     * 获取字符串的长度
     * @since redis 2.2.0
     * @param key 键
     * @return 返回字符串长度
     */
    public Long length(String key){
        return this.stringOperations.size(key);
    }

    /**
     * 自增
     * @since redis 2.6.0
     * @param key 键
     * @param data 步长
     * @return 返回自增后的值
     */
    public Double increment(String key, Double data){
        return this.stringOperations.increment(key, data);
    }

    /**
     * 自增
     * @since redis 1.0.0
     * @param key 键
     * @param data 步长
     * @return 返回自增后的值
     */
    public Long increment(String key, Long data){
        return this.stringOperations.increment(key, data);
    }

    /**
     * 自增
     * @since redis 1.0.0
     * @param key 键
     * @return 返回自增后的值
     */
    public Long increment(String key){
        return this.stringOperations.increment(key);
    }

    /**
     * 递减
     * @since redis 1.0.0
     * @param key 键
     * @param data 步长
     * @return 返回递减后的值
     */
    public Long decrement(String key, Long data){
        return this.stringOperations.decrement(key, data);
    }

    /**
     * 递减
     * @since redis 1.0.0
     * @param key 键
     * @return 返回递减后的值
     */
    public Long decrement(String key){
        return this.stringOperations.decrement(key);
    }
}
